/**
 * 将json转化为spec
 * @param json
 */

import {forEach, includes, isArray, isBoolean, isNil, isNumber, isObject, isString, keys, map} from 'lodash-es';
import {
    UnionSpecItem,
    ListSpecItem,
    StringSpecItem,
    ObjectSpecItem,
    NumberSpecItem,
    BoolSpecItem,
    AudioUploadSpecItem,
    VideoUploadSpecItem,
    UploadSpecItem,
    UrlSpecItem,
    ColorSpecItem,
    HtmlSpecItem,
    AlternativeSpecItem
} from '@jsw/report-core';

export const genListSpecItem = (key: string, displayName?: string) => {
    const spec: ListSpecItem = {
        name: key,
        displayName: displayName || '列表',
        dataType: 'LIST',
        needFilled: true,
        rules: {
            required: true,
            minCount: 1,
            maxCount: 5
        },
        extraAttr: {
            initialCount: 3
        }
    };
    return spec;
};

export const genObjectSpecItem = (key: string, displayName?: string) => {
    const spec: ObjectSpecItem = {
        name: key,
        displayName: displayName || key,
        dataType: 'OBJECT',
        needFilled: true,
        rules: {
            required: true
        },
        extraAttr: {}
    };
    return spec;
};

export const genBoolSpecItem = (key: string, displayName?: string) => {
    const spec: BoolSpecItem = {
        name: key,
        displayName: displayName || '是/否',
        dataType: 'BOOL',
        needFilled: true,
        rules: {
            required: true
        },
        extraAttr: {}
    };
    return spec;
};

export const genNumberSpecItem = (key: string, displayName?: string) => {
    const spec: NumberSpecItem = {
        name: key,
        displayName: displayName || '数字',
        dataType: 'NUMBER',
        needFilled: true,
        rules: {
            required: true,
            int: true,
            min: 1,
            max: 1000
        },
        extraAttr: {}
    };
    return spec;
};
export const genAudioUploadSpecItem = (key: string, displayName?: string) => {
    const spec: AudioUploadSpecItem = {
        name: key,
        displayName: displayName || '音频',
        dataType: 'AUDIO',
        needFilled: true,
        rules: {
            required: true,
            audioUrl: true
        },
        extraAttr: {
            ext: 'mp3',
            maxSize: 500
        }
    };
    return spec;
};
export const genVideoUploadSpecItem = (key: string, displayName?: string) => {
    const spec: VideoUploadSpecItem = {
        name: key,
        displayName: displayName || '视频',
        dataType: 'VIDEO',
        needFilled: true,
        rules: {
            required: true,
            videoUrl: true
        },
        extraAttr: {
            formats: ['.mp4'],
            size: [0, 100],
            duration: [0, 600],
            width: 100,
            height: 100
        }
    };
    return spec;
};
export const genImageUploadSpecItem = (key: string, displayName?: string) => {
    const spec: UploadSpecItem = {
        name: key,
        displayName: displayName || '图片',
        dataType: 'UPLOAD',
        needFilled: true,
        rules: {
            required: true,
            imageUrl: true
        },
        extraAttr: {
            maxSize: 200,
            ext: 'jpg,png',
            width: 100,
            height: 100
        }
    };
    return spec;
};
export const genUrlSpecItem = (key: string, displayName?: string) => {
    const spec: UrlSpecItem = {
        name: key,
        displayName: displayName || '跳转地址',
        dataType: 'URL',
        needFilled: true,
        rules: {
            required: true
        },
        extraAttr: {}
    };
    return spec;
};

export const genColorSpecItem = (key: string, displayName?: string) => {
    const spec: ColorSpecItem = {
        name: key,
        displayName: displayName || '颜色',
        dataType: 'COLOR',
        needFilled: true,
        rules: {
            required: true
        },
        extraAttr: {
            colorConfig: {
                presetColors: [
                    {value: '#ff0000', label: '红色'},
                    {value: '#00ff00', label: '绿色'},
                    {value: '#0000ff', label: '蓝色'}
                ],
                allowCustom: true
            }
        }
    };
    return spec;
};

export const genStringSpecItem = (key: string, displayName?: string) => {
    const spec: StringSpecItem = {
        name: key,
        displayName: displayName || key,
        dataType: 'STRING',
        needFilled: true,
        rules: {
            required: true,
            minByteLength: 0,
            maxByteLength: 10
        },
        extraAttr: {}
    };
    return spec;
};
export const genHtmlSpecItem = (key: string, displayName?: string) => {
    const spec: HtmlSpecItem = {
        name: key,
        displayName: displayName || key,
        dataType: 'HTML',
        needFilled: true,
        rules: {
            required: true,
            minTextByteLength: 0,
            maxTextByteLength: 10,
            tagList: {
                em: {
                    minCount: 0,
                    maxCount: 1,
                    minTextByteLength: 0,
                    maxTextByteLength: 10
                }
            }
        },
        extraAttr: {
            editorConfig: {
                allowItalicTag: true
            }
        }
    };
    return spec;
};
export const genAlternativeSpecItem = (key: string, displayName?: string) => {
    const spec: AlternativeSpecItem = {
        name: key,
        displayName: displayName || '下拉选项',
        dataType: 'ALTERNATIVE',
        needFilled: true,
        rules: {
            required: true
        },
        extraAttr: {
            requireInitValue: false
        }
    };
    return spec;
};

export const convertJson2Spec = (json: Record<string, any>): UnionSpecItem[] => {
    const spec: UnionSpecItem[] = [];
    const childrenKeys = keys(json);
    forEach(childrenKeys, (key) => {
        const itemValue = json[key];
        if (isArray(itemValue)) {
            const listSpec = genListSpecItem(key);
            const firstValue = itemValue[0];
            if (isObject(firstValue)) {
                listSpec.items = convertJson2Spec(firstValue);
            } else if (!isNil(firstValue)) {
                listSpec.element = genStringSpecItem(key, `${firstValue}`);
            }
            spec.push(listSpec);
        } else if (isObject(itemValue)) {
            const objectSpec = genObjectSpecItem(key);
            objectSpec.items = convertJson2Spec(itemValue);
            spec.push(objectSpec);
        } else if (isNumber(itemValue)) {
            spec.push(genNumberSpecItem(key));
        } else if (isBoolean(itemValue)) {
            spec.push(genBoolSpecItem(key));
        } else if (isString(itemValue)) {
            if (/^https?:\/\//i.test(itemValue)) {
                if (/\.mp3$/i.test(itemValue)) {
                    spec.push(genAudioUploadSpecItem(key));
                } else if (/\.mp4$/i.test(itemValue)) {
                    spec.push(genVideoUploadSpecItem(key));
                } else if (/\.(jpg|jpeg|png|gif)$/i.test(itemValue)) {
                    spec.push(genImageUploadSpecItem(key));
                } else {
                    spec.push(genUrlSpecItem(key));
                }
            } else if (/^#[0-9a-f]{6,6}$/i.test(itemValue)) {
                spec.push(genColorSpecItem(key));
            } else {
                spec.push(genStringSpecItem(key, itemValue));
            }
        }
    });
    return spec;
};

const stringLikeDatatype = ['STRING', 'URL', 'COLOR', 'NUMBER', 'HTML', 'AUDIO', 'VIDEO', 'UPLOAD', 'BOOL'];
const objectLikeDatatype = ['ALTERNATIVE', 'OBJECT'];

const DatatypeEnumLabelMap: Record<string, string> = {
    ['STRING']: '字符串',
    ['NUMBER']: '数字',
    ['UPLOAD']: '图片',
    ['AUDIO']: '音频',
    ['VIDEO']: '视频',
    ['COLOR']: '颜色',
    ['URL']: '链接',
    ['HTML']: '富文本',
    ['ALTERNATIVE']: '下拉选项(单选)',
    ['OBJECT']: '对象',
    ['ENUM']: '枚举',
    ['BOOL']: '布尔',
    ['LIST']: '列表',
    ['ACTIONLINK']: '动作链接'
};

export const getDatatypeOptions = (dataType: string) => {
    if (includes(stringLikeDatatype, dataType)) {
        return map(stringLikeDatatype, (type) => ({label: `${DatatypeEnumLabelMap[type]}`, value: type}));
    } else if (includes(objectLikeDatatype, dataType)) {
        return map(objectLikeDatatype, (type) => ({label: `${DatatypeEnumLabelMap[type]}`, value: type}));
    }
    return [];
};
